/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.admin.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.api.R;
import org.springblade.modules.admin.dto.PlanContentSaveDto;
import org.springblade.modules.admin.dto.rescue.PlanAddUserDTO;
import org.springblade.modules.admin.dto.rescue.PlanAddUserSearchDTO;
import org.springblade.modules.admin.dto.rescue.RescueListDTO;
import org.springblade.modules.admin.vo.*;
import org.springblade.modules.admin.vo.plan.PlanRescueDetailVO;
import org.springblade.modules.admin.vo.plan.TodayTaskListVO;
import org.springblade.modules.admin.vo.plan.wx.UserTodayPlanDetailVo;
import org.springblade.modules.admin.vo.rescue.*;
import org.springblade.modules.admin.vo.rescue.map.MapRescueBuildingDetailVO;
import org.springblade.modules.admin.vo.rescue.map.MapRescueBuildingListVO;
import org.springblade.modules.admin.vo.rescue.map.MapRescuePlanDetailVO;
import org.springblade.modules.admin.vo.rescue.map.MapUserInfoCardDetailPlanListVO;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.admin.service.IMaintainMalfunctionRescueService;
import org.springblade.core.boot.ctrl.BladeController;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.Struct;
import java.util.*;


/**
 * 救援工单明细 控制器
 *
 * @author ysq
 * @since 2023-02-25
 */
@RestController
@AllArgsConstructor
@RequestMapping("admin/maintain/malfunction/rescue")
@Api(value = "救援工单明细", tags = "救援工单明细接口")
public class MaintainMalfunctionRescueController extends BladeController {

	private final IMaintainMalfunctionRescueService maintainMalfunctionRescueService;

	/**
	 * 详情
	 */
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情")
	public R<RescuePlanDetail> detail(Long planId) {
		RescuePlanDetail detail = maintainMalfunctionRescueService.detail(planId);
		return R.data(detail);
	}

	/**
	 * 分页 救援工单明细
	 */
	@PostMapping("/list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "分页")
	public R<IPage<RescueListVo>> list(@RequestBody RescueListDTO rescueListDTO, @RequestBody Query query) {
		IPage<RescueListVo> pages = maintainMalfunctionRescueService.selectMaintainMalfunctionRescuePage(Condition.getPage(query), rescueListDTO);
		return R.data(pages);
	}


	/**
	 * 获取救援任务的统计信息
	 *
	 * @return 统计结果
	 */
	@GetMapping("/getPlanStatistic")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "救援统计信息")
	public R<PlanStatisticVo> getPlanStatistic() {
		PlanStatisticVo planStatisticVo = maintainMalfunctionRescueService.getPlanStatistic();
		return R.data(planStatisticVo);
	}


	/**
	 * @param elevatorIds 电梯id
	 * @param planId      工单id
	 * @param type        1:电梯责任人2:负责组，3：上次维保人员,4:已经分配人员,转派时获取
	 * @return 数据集
	 */
	@GetMapping("/getUserList")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "获取指派人员列表")
	public R<List<UserInfoVo>> getUserList(String elevatorIds, Integer type, Long planId, String userName) {
		if (StrUtil.isEmpty(elevatorIds)) {
			throw new ServiceException("电梯elevatorIds必传");
		}
		List<Long> elevatorIdss = new ArrayList<>(5);
		String[] split = elevatorIds.split(",");
		for (int i = 0; i < split.length; i++) {
			elevatorIdss.add(Convert.toLong(split[i]));
		}
		List<UserInfoVo> list = maintainMalfunctionRescueService.getUserList(elevatorIdss, type, planId, userName);
		return R.data(list);
	}


	@PostMapping("/getUserList/v2")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "获取指派人员列表plus")
	public R<List<UserInfoVo>> getUserList(@RequestBody PlanAddUserSearchDTO planAddUserSearchDTO) {
		List<UserInfoVo> list = maintainMalfunctionRescueService.getUserListV2(planAddUserSearchDTO);
		return R.data(list);
	}

	@GetMapping("/user/plan/info")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "获取人员当天的工单信息")
	public R<UserTodayPlanDetailVo> userPlanInfo(Long userId) {
		UserTodayPlanDetailVo userTodayPlanDetail = maintainMalfunctionRescueService.userPlanInfo(userId);
		return R.data(userTodayPlanDetail);
	}


	/**
	 * 救援任务撤销操作
	 *
	 * @param planId 工单id
	 * @return 数据集
	 */
	@GetMapping("/resuceCancel")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "救援撤销")
	public R<Boolean> rescueCancel(Long planId) {
		return R.data(maintainMalfunctionRescueService.rescueCancel(planId, 0));
	}

	/**
	 * 梯联网-救援任务撤销操作
	 *
	 * @param planId 工单id
	 * @return 数据集
	 */
	@TenantIgnore
	@GetMapping("/tlw/cancel")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "梯联网-救援撤销")
	public R<Boolean> tlwRescueCancel(Long planId) {
		return R.data(maintainMalfunctionRescueService.rescueCancel(planId, 1));
	}


	/**
	 * 分配工单
	 *
	 * @param planAddUserDTO 参数值
	 * @return 数据集
	 */
	@PostMapping("/planAddUser")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "工单分配人员")
	public R<Boolean> planAddUser(@RequestBody PlanAddUserDTO planAddUserDTO) {
		if (planAddUserDTO.getPlanId() == null) {
			throw new ServiceException("工单id必传");
		}
		return R.data(maintainMalfunctionRescueService.planAddUser(planAddUserDTO));
	}

	@GetMapping("/getRescueElevatorInfo")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "获取救援工单电梯信息")
	public R<RescueElevatorInfoVo> getRescueElevatorInfo(Long elevatorId) {
		return R.data(maintainMalfunctionRescueService.getRescueElevatorInfo(elevatorId, null, null));
	}

	@GetMapping("/mapUserList")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "地图-救援人员列表")
	public R<List<MapUserInfoVO>> mapUserList(@ApiParam(value = "人员状态筛选: 1-保养中，2-维修中，3-救援中，4-空闲，5-今日已打卡") @RequestParam(required = false) List<Integer> userStatus,
											  @ApiParam(value = "工单id") @RequestParam(required = false) Long planId) {
		return R.data(maintainMalfunctionRescueService.mapUserList(userStatus, planId));
	}

	@GetMapping("/screenMapUserList")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "大屏地图-人员列表")
	public R<List<MapUserInfoVO>> screenMapUserList(@ApiParam(value = "姓名搜索") @RequestParam(required = false) String search,
													@ApiParam(value = "交通工具搜索") @RequestParam(required = false) String vehicles,
													@ApiParam(value = "出勤状态搜索") @RequestParam(required = false) String isSign,
													@ApiParam(value = "工作状态搜索") @RequestParam(required = false) String planTypes,
													@ApiParam(value = "定位最后更新时间范围") @RequestParam(required = false) Integer searchMin,
													@ApiParam(value = "是否只显示救援人员") @RequestParam(required = false) boolean isOnlyShowRescue) {
		return R.data(maintainMalfunctionRescueService.screenMapUserList(search, vehicles, isSign, planTypes, searchMin, isOnlyShowRescue));
	}

	@GetMapping("/mapUserDetail")
	@ApiOperationSupport(order = 9)
	@ApiOperation(value = "地图-救援人员详情")
	public R<List<MapUserInfoCardDetailVO>> mapUserDetails(@ApiParam(value = "用户id集合", required = true) @RequestParam List<Long> userIds,
														   @ApiParam(value = "电梯id") @RequestParam(required = false) Long elevatorId,
														   @ApiParam(value = "工单id") @RequestParam(required = false) Long planId) {
		return R.data(maintainMalfunctionRescueService.mapUserCardDetails(userIds, elevatorId, planId));
	}

	@GetMapping("/mapUserScreenDetail")
	@ApiOperationSupport(order = 9)
	@ApiOperation(value = "大屏地图-人员详情")
	public R<MapUserInfoCardDetailVO> mapUserScreenDetail(@ApiParam(value = "用户id", required = true) @RequestParam Long userId) {
		return R.data(maintainMalfunctionRescueService.mapUserScreenDetail(userId));
	}

	@GetMapping("/mapUserScreenDetail/plan/list")
	@ApiOperationSupport(order = 9)
	@ApiOperation(value = "大屏地图-人员详情")
	public R<List<MapUserInfoCardDetailPlanListVO>> mapUserScreenDetailPlanList(@ApiParam(value = "用户id", required = true) @RequestParam Long userId, Integer typeStatus) {
		return R.data(maintainMalfunctionRescueService.mapUserScreenDetailPlanList(userId, typeStatus));
	}

	@GetMapping("tlw/rescue/detail")
	@ApiOperationSupport(order = 10)
	@ApiOperation(value = "梯联网-救援详情")
	public R<TlwRescueDetailVO> tlwRescueDetail(@ApiParam(value = "报警id", required = true) @RequestParam String tlwJoinId) {
		return R.data(maintainMalfunctionRescueService.tlwRescueDetail(tlwJoinId));
	}

	@GetMapping("/maintain/building/list")
	@ApiOperationSupport(order = 11)
	@ApiOperation(value = "在保项目列表")
	public R<List<MaintainBuildingListVO>> maintainBuildingList(@RequestParam(required = false) String search) {
		return R.data(maintainMalfunctionRescueService.maintainBuildingList(search));
	}

	@GetMapping("/effective/building/list")
	@ApiOperationSupport(order = 11)
	@ApiOperation(value = "筛选-在保项目列表")
	public R<List<EffectiveBuildingVO>> effectiveBuildingList(@ApiParam(value = "项目名称") @RequestParam(required = false) String buildingName,
															  @ApiParam(value = "项目地址") @RequestParam(required = false) String address,
															  @ApiParam(value = "项目联系人手机号") @RequestParam(required = false) String phone,
															  @ApiParam(value = "是否只显示救援项目") @RequestParam(required = false) boolean isOnlyShowRescue) {
		return R.data(maintainMalfunctionRescueService.effectiveBuildingList(buildingName, address, phone, isOnlyShowRescue));
	}

	@GetMapping("/effective/elevator/list")
	@ApiOperationSupport(order = 11)
	@ApiOperation(value = "筛选-在保电梯列表")
	public R<List<EffectiveElevatorVO>> effectiveElevatorList(@ApiParam(value = "项目id") @RequestParam(required = false) String buildingId,
															  @ApiParam(value = "电梯识别码") @RequestParam(required = false) String elevatorNum,
															  @ApiParam(value = "是否只显示救援电梯") @RequestParam(required = false) boolean isOnlyShowRescue) {
		return R.data(maintainMalfunctionRescueService.effectiveElevatorList(buildingId, elevatorNum, isOnlyShowRescue));
	}

	@GetMapping("/map/rescue/building/list")
	@ApiOperationSupport(order = 12)
	@ApiOperation(value = "项目救援预警列表")
	public R<List<MapRescueBuildingListVO>> mapRescueBuildingList(@ApiParam(value = "搜索") @RequestParam(required = false) String search,
																  @ApiParam(value = "是否只显示救援项目") @RequestParam(required = false) boolean isOnlyShowRescue) {
		return R.data(maintainMalfunctionRescueService.mapRescueBuildingList(search, isOnlyShowRescue));
	}

	@GetMapping("/map/rescue/building/detail")
	@ApiOperationSupport(order = 12)
	@ApiOperation(value = "项目救援预警详情")
	public R<MapRescueBuildingDetailVO> mapRescueBuildingDetail(Long buildingId) {
		return R.data(maintainMalfunctionRescueService.mapRescueBuildingDetail(buildingId));
	}

	@GetMapping("rescue/project/screen")
	@ApiOperationSupport(order = 12)
	@ApiOperation(value = "救援中项目统计")
	public R<Map<String, Object>> rescueProjectScreen() {
		return R.data(maintainMalfunctionRescueService.rescueProjectScreen());
	}

	@GetMapping("/map/rescue/building/recently/user")
	@ApiOperationSupport(order = 13)
	@ApiOperation(value = "项目最近人员")
	public R<List<MapUserInfoVO>> mapRescueBuildingRecentlyUser(@ApiParam(required = true, value = "项目id") @RequestParam Long buildingId,
																@ApiParam(value = "交通工具") @RequestParam(required = false) List<String> vehicle,
																@ApiParam(value = "工作状态【1-空闲中，2-救援，3-维修，4-保养】") @RequestParam(required = false) List<Integer> workStatus,
																@ApiParam(value = "半径范围") @RequestParam(required = false) Integer distance,
																@ApiParam(value = "签到状态 1-已出勤，2-未出勤") @RequestParam(required = false) List<Integer> isSign,
																@ApiParam(value = "定位最后更新时间") @RequestParam(required = false) Integer searchMin,
																@ApiParam(value = "电梯id") @RequestParam(required = false) Long elevatorId,
																@ApiParam(value = "技能等级") @RequestParam(required = false) List<String> skillKeys,
																@ApiParam(value = "关键字") @RequestParam(required = false) String keyword) {
		return R.data(maintainMalfunctionRescueService.mapRescueBuildingRecentlyUser(buildingId, vehicle, workStatus, distance, isSign, searchMin, elevatorId, skillKeys, keyword));
	}

	@GetMapping("/map/rescue/building/recently/maintain/user")
	@ApiOperationSupport(order = 13)
	@ApiOperation(value = "附近项目今日保养人员")
	public R<List<MapUserInfoVO>> mapRescueBuildingRecentlyMaintainUser(@ApiParam(required = true, value = "项目id") @RequestParam Long buildingId,
																		@ApiParam(value = "交通工具") @RequestParam(required = false) List<String> vehicle,
																		@ApiParam(value = "工作状态【1-空闲中，2-救援，3-维修，4-保养】") @RequestParam(required = false) List<Integer> workStatus,
																		@ApiParam(value = "半径范围") @RequestParam(required = false) Integer distance,
																		@ApiParam(value = "签到状态 1-已出勤，2-未出勤") @RequestParam(required = false) List<Integer> isSign,
																		@ApiParam(value = "定位最后更新时间") @RequestParam(required = false) Integer searchMin,
																		@ApiParam(value = "电梯id") @RequestParam(required = false) Long elevatorId,
																		@ApiParam(value = "技能等级") @RequestParam(required = false) List<String> skillKeys,
																		@ApiParam(value = "关键字") @RequestParam(required = false) String keyword) {
		return R.data(maintainMalfunctionRescueService.mapRescueBuildingRecentlyMaintainUser(buildingId, vehicle, workStatus, distance, isSign, searchMin, elevatorId, skillKeys, keyword));
	}

	@GetMapping("/map/rescue/building/recently/building/user")
	@ApiOperationSupport(order = 13)
	@ApiOperation(value = "项目附近居住人员")
	public R<List<MapUserInfoVO>> mapRescueBuildingRecentlyBulidingUser(@ApiParam(required = true, value = "项目id") @RequestParam Long buildingId,
																		@ApiParam(value = "交通工具") @RequestParam(required = false) List<String> vehicle,
																		@ApiParam(value = "工作状态【1-空闲中，2-救援，3-维修，4-保养】") @RequestParam(required = false) List<Integer> workStatus,
																		@ApiParam(value = "半径范围") @RequestParam(required = false) Integer distance,
																		@ApiParam(value = "签到状态 1-已出勤，2-未出勤") @RequestParam(required = false) List<Integer> isSign,
																		@ApiParam(value = "定位最后更新时间") @RequestParam(required = false) Integer searchMin,
																		@ApiParam(value = "电梯id") @RequestParam(required = false) Long elevatorId,
																		@ApiParam(value = "技能等级") @RequestParam(required = false) List<String> skillKeys,
																		@ApiParam(value = "关键字") @RequestParam(required = false) String keyword) {
		return R.data(maintainMalfunctionRescueService.mapRescueBuildingRecentlyBuildingUser(buildingId, vehicle, workStatus, distance, isSign, searchMin, elevatorId, skillKeys, keyword));
	}

	@GetMapping("/map/rescue/user/recently/building")
	@ApiOperationSupport(order = 13)
	@ApiOperation(value = "人员最近项目")
	public R<List<MaintainBuildingListVO>> mapRescueUserRecentlyBuilding(Long userId) {
		return R.data(maintainMalfunctionRescueService.mapRescueUserRecentlyBuilding(userId));
	}

	@TenantIgnore
	@GetMapping("/tlw/plan/rescue/user/coordinate")
	@ApiOperationSupport(order = 14)
	@ApiOperation(value = "梯联网-救援人员坐标")
	public R<MapUserInfoDetailVO> tlwPlanRescueUserCoordinate(Long planId) {
		return R.data(maintainMalfunctionRescueService.tlwPlanRescueUserCoordinate(planId));
	}

	@TenantIgnore
	@GetMapping("/map/building/detail/elevator/list")
	@ApiOperation(value = "救援大屏-项目详情电梯列表")
	public R<Map<String, Object>> mapBuildingDetailElevatorList(Long buildingId, String keyword) {
		return R.data(maintainMalfunctionRescueService.mapBuildingDetailElevatorList(buildingId, keyword));
	}

	@GetMapping("/plan/rescue/detail/list")
	@ApiOperationSupport(order = 15)
	@ApiOperation(value = "救援详情列表")
	public R<MapRescuePlanDetailVO> planRescueDetailList(@ApiParam(required = true, value = "项目id") @RequestParam Long buildingId,
														 @ApiParam(value = "电梯id") @RequestParam(required = false) Long elevatorId) {
		return R.data(maintainMalfunctionRescueService.planRescueDetailList(buildingId, elevatorId));
	}

	@GetMapping("/get/elevator/device/status")
	@ApiOperationSupport(order = 16)
	@ApiOperation(value = "获取救援电梯设备状态")
	public R<DeviceStatusVO> getElevatorDeviceStatus(@ApiParam(required = true, value = "电梯id") @RequestParam Long elevatorId) {
		return R.data(maintainMalfunctionRescueService.getElevatorDeviceStatus(elevatorId));
	}

	@GetMapping("/get/rescue/detail")
	@ApiOperationSupport(order = 17)
	@ApiOperation(value = "获取救援工单详情")
	public R<PlanRescueDetailVO> getRescueDetail(@ApiParam(required = true, value = "工单id") @RequestParam Long planId) {
		return R.data(maintainMalfunctionRescueService.getRescueDetail(planId));
	}

	@GetMapping("/get/rescue/users")
	@ApiOperationSupport(order = 18)
	@ApiOperation(value = "获取救援工单救援人员")
	public R<List<MapUserInfoDetailVO>> getRescueUsers(@ApiParam(required = true, value = "工单id") @RequestParam Long planId) {
		return R.data(maintainMalfunctionRescueService.mapUserDetails(planId));
	}

	@GetMapping("/get/today/task/list")
	@ApiOperationSupport(order = 19)
	@ApiOperation(value = "获取今日任务列表")
	public R<List<TodayTaskListVO>> getTodayTaskList(@ApiParam(required = true, value = "用户id") @RequestParam Long userId,
													 @ApiParam(required = false, value = "工单类型") @RequestParam Integer typeStatus) {
		return R.data(maintainMalfunctionRescueService.getTodayTaskList(typeStatus, userId));
	}


	@GetMapping("/maintain/building/elevator/count")
	@ApiOperation(value = "获取救援大屏项目电梯总览统计")
	public R<Map<String, Object>> getMaintainBuildingElevatorCount() {
		return R.data(maintainMalfunctionRescueService.getMaintainBuildingElevatorCount());
	}

	@GetMapping("/plan/result/count")
	@ApiOperation(value = "获取救援大屏今日救援统计")
	public R<Map<String, Object>> getPlanResultCount() {
		return R.data(maintainMalfunctionRescueService.getPlanResultCount());
	}

	@PostMapping("/list/down/excel")
	@ApiOperation(value = "下载救援工单")
	public void listDownExcel(HttpServletResponse response, @RequestBody RescueListDTO rescueListDTO) throws IOException {
		Query query = new Query();
		query.setSize(-1);
		ExcelWriter excelWriter = null;
		ServletOutputStream outputStream = response.getOutputStream();
		try {
			List<List<String>> rows = new ArrayList<>();
			List<String> title = CollUtil.newArrayList
				("任务编号", "项目名称", "电梯位置", "调度人员", "实际救援人员", "维保组", "报警人", "报警类型", "报警来源", "报警时间", "调度时间",
					"到达时间", "救援完成时间", "到达用时(分钟)", "救援用时(分钟)", "是否超时到达", "是否转派其它组", "报警描述", "任务指派", "救援状态",
					"关联维修单", "维修单状态", "故障原因", "维修单创建时间", "维修单完成时间");
			rows.add(title);
			List<RescueListVo> records = maintainMalfunctionRescueService.selectMaintainMalfunctionRescuePage(Condition.getPage(query), rescueListDTO).getRecords();
			for (RescueListVo rescueListVo : records) {
				List<String> row = new ArrayList<>(16);
				row.add(Convert.toStr(rescueListVo.getId()));
				row.add(Convert.toStr(rescueListVo.getBuildingName()));
				row.add(Convert.toStr(rescueListVo.getElevatorAddress(), "/"));
				row.add(Convert.toStr(rescueListVo.getPersonnelRealNames(), "/"));
				row.add(Convert.toStr(rescueListVo.getMaintainName(), "/"));
				row.add(Convert.toStr(rescueListVo.getGroupName(), "/"));
				row.add(Convert.toStr(rescueListVo.getRescueName() + rescueListVo.getRescuePhone()));
				row.add(Convert.toStr(rescueListVo.getRescueTypeName()));
				row.add(Convert.toStr(rescueListVo.getRescueSourceName()));
				row.add(Convert.toStr(DateUtil.format(rescueListVo.getCreateTime(), "yyyy-MM-dd HH:mm:ss")));
				row.add(Convert.toStr(DateUtil.format(rescueListVo.getAllocateTime(), "yyyy-MM-dd HH:mm:ss"), "/"));
				row.add(Convert.toStr(DateUtil.format(rescueListVo.getArriveTime(), "yyyy-MM-dd HH:mm:ss"), "/"));
				row.add(Convert.toStr(DateUtil.format(rescueListVo.getPlanEndTime(), "yyyy-MM-dd HH:mm:ss"), "/"));
				row.add(Convert.toStr(rescueListVo.getArriveMinute(), "/"));
				row.add(Convert.toStr(rescueListVo.getUseMinute(), "/"));
				row.add(Convert.toStr(rescueListVo.getIsOvertimeArrival() == null ?  "/" : rescueListVo.getIsOvertimeArrival() ? "超时达" : "准时达", "/"));
				row.add(Convert.toStr(rescueListVo.getIsTransferDept() == null ? "/" : rescueListVo.getIsTransferDept() ? "是" : "否", "/"));
				row.add(Convert.toStr(rescueListVo.getRescueDesc()));
				row.add(Convert.toStr(rescueListVo.getIsHasUser() == 0 ? "未指派" : "已指派"));
				row.add(Convert.toStr(rescueListVo.getStatusName()));
				row.add(Convert.toStr(rescueListVo.getMalId(), "/"));
				row.add(Convert.toStr(rescueListVo.getMalStatusName(), "/"));
				row.add(Convert.toStr(rescueListVo.getFaultReasons(), "/"));
				row.add(Convert.toStr(DateUtil.format(rescueListVo.getMalCreateTime(), "yyyy-MM-dd HH:mm:ss"), "/"));
				row.add(Convert.toStr(DateUtil.format(rescueListVo.getMalPlanEndTime(), "yyyy-MM-dd HH:mm:ss"), "/"));
				rows.add(row);
			}
			String fileName = DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
			setResponseHeader(response, fileName);
			excelWriter = ExcelUtil.getBigWriter(rows.size());
			excelWriter.write(rows, true);
			excelWriter.flush(outputStream, true);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (excelWriter != null) {
				excelWriter.close();
			}
			outputStream.close();
		}
	}


	/**
	 * 功能描述: 发送响应流方法
	 */
	private void setResponseHeader(HttpServletResponse response, String fileName) {
		try {
			try {
				fileName = new String(fileName.getBytes(), "ISO8859-1");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			response.setContentType("application/octet-stream;charset=ISO8859-1");
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
			response.addHeader("Pargam", "no-cache");
			response.addHeader("Cache-Control", "no-cache");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	@GetMapping("/dispatcher/page")
	@ApiOperationSupport(order = 20)
	@ApiOperation(value = "调度分页")
	public R<IPage<DispatcherPageRespVO>> dispatcherPage(DispatcherPageReqVO dispatcherPageReqVO, Query query){
		return R.data(maintainMalfunctionRescueService.dispatcherPage(dispatcherPageReqVO, Condition.getPage(query)));
	}

	@GetMapping("/dispatcher/statistics")
	@ApiOperationSupport(order = 21)
	@ApiOperation(value = "调度统计")
	public R<DispatcherStatisticsVO> dispatcherStatistics(DispatcherPageReqVO dispatcherPageReqVO){
		return R.data(maintainMalfunctionRescueService.dispatcherStatistics(dispatcherPageReqVO));
	}

	@GetMapping("/has/rela/mal/order")
	@ApiOperationSupport(order = 22)
	@ApiOperation(value = "判断是否有关联的维修单")
	public R<Boolean> hasRelaMalOrder(Long id){
		return R.data(maintainMalfunctionRescueService.hasRelaMalOrder(id));
	}

	/**
	 * 维修报障新增
	 */
	@PostMapping("/report/mal")
	@ApiOperationSupport(order = 23)
	@ApiOperation(value = "上报维修")
	public R<Long> reportMal(@Valid @RequestBody PlanContentSaveDto planContentSaveDto) {
		return R.data(maintainMalfunctionRescueService.reportMal(planContentSaveDto));
	}

	/**
	 * 催办
	 */
	@GetMapping("/reminder")
	@ApiOperationSupport(order = 24)
	@ApiOperation(value = "催办")
	public R<Boolean> reminder(@ApiParam (value = "工单id", required = true) @RequestParam Long planId) {
		return R.data(maintainMalfunctionRescueService.reminder(planId));
	}
}
